home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1990: Night of the Living Disc / Night of the Living Disc.2mg / Dev.CD.5 / Tools / DTS.Samples / SC09Lister / Event.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-25  |  15.5 KB  |  392 lines  |  [B0] Apple IIgs Source Code (0x000A)

  1. /**********************************************************************
  2. *
  3. * lister event.c -- Version 3.0
  4. *
  5. * Developer Technical Support Apple II Sample Code
  6. *
  7. * Copyright (c)
  8. * Apple Computer, Inc.  1988-1990
  9. * All Rights Reserved.
  10. *
  11. * Written by Eric Soldan.
  12. *
  13. * This file contains the code which implements the 
  14. * main event loop used by the lister program.
  15. *
  16. **********************************************************************/
  17.  
  18. #include <types.h>
  19. #include <event.h>
  20. #include <font.h>
  21. #include <intmath.h>
  22. #include <lineedit.h>
  23. #include <locator.h>
  24. #include <menu.h>
  25. #include <resources.h>
  26. #include <window.h>
  27.  
  28. #include "lister.h"
  29.  
  30. void    doChangeTabs();
  31. void    getTabsInfo();
  32. void    i2pstr();
  33. void    mainWindowDraw();
  34.  
  35. /**********************************************************************
  36. *
  37. * mainEvent
  38. *
  39. * This is the main part of the program.  The program cycles in this
  40. * loop until the user chooses quit.
  41. *
  42. **********************************************************************/
  43.  
  44. void    mainEvent()
  45. {
  46.     WindowPtr       wptr, keepPort;
  47.     unsigned long   id;
  48.     unsigned int    item, rad, i, part, val;
  49.     FontID          newFont;
  50.     CtlRecHndl      ctlHndl;
  51.  
  52.     zapLocals();
  53.  
  54.     keepPort = GetPort();
  55.  
  56.     wptr = NewWindow2(NULL, NULL, NULL, NULL, 2, MainWindowID, rWindParam1);
  57.     if (!_toolErr) {
  58.  
  59.         mainWindow = wptr;
  60.  
  61.             /* This gets kind of weird here.  The MainWindow also includes
  62.             ** some of the TabsWindow controls.  This is so that the data
  63.             ** in the resources is loaded in.  The info is then extracted,
  64.             ** and then the controls are disposed of.  Once all of this is
  65.             ** done, the window is made visible.  This is actually the
  66.             ** easiest way to initially get the data from the TabsWindow
  67.             ** control resources. */
  68.  
  69.         getTabsInfo();      /* Extract tabs data and put in print structure. */
  70.  
  71.         for (i = (unsigned int)TabsData; i < (unsigned int)(TabChr + 1); i++)
  72.             DisposeControl(GetCtlHandleFromID(wptr, (long)i));
  73.                 /* Dispose the TabsWindow controls. */
  74.  
  75.         MakeThisCtlTarget(GetCtlHandleFromID(mainWindow, Header));
  76.             /* Depending on the order of the controls, we may have just deleted
  77.             ** the target control.  Make sure we have a target. */
  78.  
  79.  
  80.         ShowWindow(wptr);       /* Now that everything is okay, show window. */
  81.         SelectWindow(wptr);
  82.  
  83.         for (;;) {
  84.             id = fakeModalDialog(&event, mainWindowDraw, handleKeys, NULL,
  85.                 fmdMenuSelect+
  86.                 fmdMenuKey+
  87.                 fmdIBeam+
  88.                 fmdDeskAcc+
  89.                 fmdUpdateAll+
  90.                 fmdMovable
  91.             );
  92.             item = id;
  93.             if (id & 0x80000000L) {     /* Hi-bit on?  It's a menu command. */
  94.                 doMenuCommand(id);
  95.                 if (quitFlag) break;    /* It was a quit menu command. */
  96.             }
  97.             else {
  98.                 switch (item) {         /* User clicked on ctl -- handle it. */
  99.                     case ChFont:
  100.                         newFont.fidLong = ChooseFont(print.theFont.fidLong, 0);
  101.                         if (newFont.fidLong) {      /* Check for cancel. */
  102.                             if (newFont.fidRec.fontSize > 42)
  103.                                 newFont.fidRec.fontSize = 42;
  104.                             print.theFont.fidLong = newFont.fidLong;
  105.                         }
  106.                         break;
  107.                     case ChangeTabs:
  108.                         doChangeTabs();
  109.                         break;
  110.                     case BoxProc:
  111.                         part    = fmdGetCtlPart();
  112.                         ctlHndl = GetCtlHandleFromID(mainWindow, BoxProc);
  113.                         val     = GetCtlValue(ctlHndl);
  114.                         val    ^= (1 << --part);
  115.                         SetCtlValue(val, ctlHndl);
  116.                         break;
  117.                 }
  118.                 if (quitFlag) break;
  119.                     /* User chose quit while tabs window was up. */
  120.             }
  121.         }
  122.  
  123.         SetPort(keepPort);
  124.         CloseWindow(wptr);
  125.         mainWindow = NULL;
  126.     }
  127. }
  128.  
  129. /**********************************************************************/
  130.  
  131. pascal void     handleKeys(event)
  132. WmTaskRec*      event;
  133. {
  134.     WindowPtr       wptr;
  135.     unsigned int    c, e, i, j, m, digitsOnly, myWind;
  136.     CtlRecHndl      ctlHndl;
  137.     LERecPtr        lePtr;
  138.  
  139.     static char     validChrs[] = {
  140.         6,      /* Allow char-right-of-cursor delete. */
  141.         8,      /* Allow left arrow. */
  142.         9,      /* Allow tab key. */
  143.         13,     /* Allow default button. */
  144.         21,     /* Allow right arrow. */
  145.         24,     /* Allow ctrl-x to clear field. */
  146.         25,     /* Allow delete to end-of-line. */
  147.         127,    /* Allow delete. */
  148.         0       /* End of list. */
  149.     };          /* These are the valid lineEdit editing keys.  Allow them. */
  150.  
  151.     zapLocals();
  152.  
  153. /*  (*ctlHndl)->ctlData = NULL;     */
  154.  
  155. /* The above commented-out code is a test of the uninitialized
  156. ** pointer testing.  If productionVersion is set to 0, then
  157. ** uninitialized pointer testing is done in this application.
  158. ** If the above commented code is uncommented, then we have just
  159. ** created an instance where an uninitialized pointer (or handle
  160. ** in this case) is used.  It doesn't matter how many levels of
  161. ** dereferencing is done.  The local checker will still find the
  162. ** problem.  If you uncomment the code above, make sure that you
  163. ** don't compile this program with the productionVersion switch
  164. ** true.  If you do this, you will be using an uninitialized
  165. ** pointer without checking for it.  You will actually be
  166. ** clobbering memory, and who knows how you will crash, or when.
  167. ** Also note that you can set the ctlHndl to NULL before using
  168. ** it.  The pointer checking code will catch this also.
  169. ** It will not, hwever catch a usage of a NULL pointer.  Using
  170. ** a NULL pointer will not index into the test bank of RAM,
  171. ** and is therefore undetectable.
  172. */
  173.  
  174.     if ( ((e = event->what) == keyDownEvt) || (e == autoKeyEvt) ) {
  175.             /* Only filter/modify key events. */
  176.  
  177.         wptr = FrontWindow();       /* Filtering varies, depends on window. */
  178.         digitsOnly = myWind = 0;    /* Initialize some flags. */
  179.  
  180.         if (wptr == mainWindow) {   /* See if front window is app. window. */
  181.             myWind++;               /* It is.                              */
  182.             if (GetCtlID(FindTargetCtl()) == Columns)
  183.                 digitsOnly++;       /* Only digits for Columns editLine ctl. */
  184.         }
  185.  
  186.         if (wptr == tabsWindow) {   /* See if front window is app. window. */
  187.             myWind++;               /* It is.                              */
  188.             digitsOnly++;           /* It is the tabs window.              */
  189.             if (GetCtlID(ctlHndl = FindTargetCtl()) == TabsData)
  190.                 digitsOnly++;       /* Allow commas and the ellipses char. */
  191.         }                           /* also for this editLine item.        */
  192.  
  193.         if (!myWind) return;        /* It is a DA, so allow everything. */
  194.  
  195.         c  = event->message & 0xFF;
  196.         m  = event->modifiers & (appleKey | shiftKey | optionKey | controlKey);
  197.  
  198.         if (!(m & appleKey)) {      /* If appleKey mod was not held down. */
  199.  
  200.             for (i = 0; j = validChrs[i]; i++) if (c == j) return;
  201.                 /* If it is a valid editLine editing character, allow it. */
  202.  
  203.             if (c == 27) {          /* Convert ESC event to OA-. event. */
  204.                 *(char *)&(event->message) = '.';
  205.                 event->modifiers |= appleKey;
  206.                 return;
  207.             }           /* This conversion of an ESC to an OA-. allows us to
  208.                         ** be able to have two key equivalents with different
  209.                         ** modifiers.  Dirrefing modifiers isn't supported by
  210.                         ** the toolbox, so we have to fake it.  Given that we
  211.                         ** can convert any event to any other event before
  212.                         ** fakeModalDialog processes it, we can have as many
  213.                         ** key equivalents for a control as we want.  We are
  214.                         ** no longer limited to two with the same modifiers.
  215.                         */
  216.  
  217.             if (digitsOnly == 2) {          /* If tabsData editLine...  */
  218.                 if (c == ',') return;       /* Commas are okay.         */
  219.                 if (c == 0xC9) {            /* Ellipses char is ok at end. */
  220.                     lePtr = *(LERecHndl)(*ctlHndl)->ctlData;
  221.                     if (lePtr->leSelEnd < lePtr->leLength)
  222.                         event->what = 0;    /* We weren't at end of line. */
  223.                     return;
  224.                 }
  225.             }       /* I realize that there are some cases missing here.
  226.                     ** I didn't feel like dealing with them.  Like, hey
  227.                     ** man, this is sample code for programmers -- cut me
  228.                     ** some slack.  One case that isn't handled is that you
  229.                     ** can type other characters after an ellipses.
  230.                     ** Therefore, the ellipses character may not end up as
  231.                     ** the end character.  I can live with this, since the
  232.                     ** tabbing code handles a comma and an ellipses
  233.                     ** character exactly the same anyway.  The ellipses
  234.                     ** is supported for user-readability.  If the user
  235.                     ** wants to put them in funny places, then fine.
  236.                     */
  237.  
  238.             if (digitsOnly) if ((c < '0') || (c > '9')) event->what = 0;
  239.                 /* If we are allowing only digits, then kill others. */
  240.  
  241.             if (c < 32) event->what = 0;
  242.                 /* Kill all control characters not previously allowed. */
  243.  
  244.             return;
  245.         }
  246.     }
  247. }
  248.  
  249. /**********************************************************************/
  250.  
  251. void    doChangeTabs()
  252. {
  253.     WindowPtr       wptr, keepPort;
  254.     unsigned long   id;
  255.     unsigned int    item;
  256.     char            str[42];
  257.  
  258.     zapLocals();
  259.  
  260.     keepPort = GetPort();
  261.  
  262.     wptr = NewWindow2(NULL, NULL, NULL, NULL, 2, TabsWindowID, rWindParam1);
  263.     if (!_toolErr) {
  264.         tabsWindow = wptr;
  265.  
  266.         fmdLESetText(wptr, TabsData, print.tabsData);
  267.         i2pstr(str, print.tabChr);
  268.         fmdLESetText(wptr, TabChr, str);
  269.             /* Since this might not be the first time this window is opened,
  270.             ** fill the LineEdit controls with the text from last time,
  271.             ** instead of using the data from the resources.
  272.             */
  273.  
  274.         for (;;) {
  275.             id = fakeModalDialog(&event, NULL, handleKeys, NULL,
  276.                 fmdMenuSelect+
  277.                 fmdMenuKey+
  278.                 fmdIBeam+
  279.                 fmdDeskAcc+
  280.                 fmdUpdateAll+
  281.                 fmdMovable
  282.             );
  283.             item = id;                              /* Get lo-word.       */
  284.             if (id & 0x80000000L) {                 /* If menu command... */
  285.                 if (item == 255) {
  286.                     HiliteMenu(0, FileMenuID);      /* Nobody else will.    */
  287.                     break;                          /* If close, then close */
  288.                 }                                   /* the tabs window.     */
  289.                 doMenuCommand(id);
  290.                 if (quitFlag) break;
  291.             }
  292.             else {
  293.                 if (item == 1) {                /* ...else handle controls. */
  294.                     getTabsInfo();              /* Extract the data before  */
  295.                     break;                      /* before closing window.   */
  296.                 }
  297.                 if (item == 2) break;           /* User cancelled.          */
  298.                 if (
  299.                     (item >= (unsigned int)MerlinTabs) && 
  300.                     (item < (unsigned int)TabsData)
  301.                 ) {
  302.                     fmdLEGetText(wptr, (unsigned long)(item + 1), str);
  303.                     fmdLESetText(wptr, TabsData, str);
  304.                 }           /* User pressed the Merlin button, or some other
  305.                             ** button that was added to the resource fork.
  306.                             ** When one of these buttons is pressed, take
  307.                             ** the data from the inactive, invisible, and way
  308.                             ** the heck outside the window lineEdit control
  309.                             ** and put it into the tabsData control.  Given
  310.                             ** the fakeModalDialog data access routines, this
  311.                             ** method of hiding the data in a lineEdit
  312.                             ** control is actually the easiest.
  313.                             */
  314.             }
  315.         }
  316.     
  317.         SetPort(keepPort);
  318.         CloseWindow(wptr);
  319.         tabsWindow = NULL;
  320.         appSetMenus();      /* This is necessary because the window just
  321.                             ** behind the one we are closing could be a DA.
  322.                             ** DA's get the activate events, and therefore
  323.                             ** fakeModalDialog doesn't get to see the
  324.                             ** activate event, and therefore doesn't get a
  325.                             ** chance to update the menus to reflect the new
  326.                             ** front window.  Due to this, we do a direct
  327.                             ** call to the menu update routine ourselves.
  328.                             ** This should be done whenever we are closing a
  329.                             ** window.  Closing a window is the only
  330.                             ** circumstance where fakeModalDialog may not
  331.                             ** automatically call the menu update routine,
  332.                             ** so we do it ourselves as a good practice.
  333.                             */
  334.     }
  335. }
  336.  
  337. /**********************************************************************/
  338.  
  339. void        getTabsInfo()
  340. {
  341.     WindowPtr       wptr;
  342.     unsigned int    i;
  343.  
  344.     zapLocals();
  345.  
  346.     wptr = mainWindow;
  347.     if (tabsWindow) wptr = tabsWindow;
  348.  
  349.         /* If we have a tabsWindow, then we want to get the data
  350.         ** from that window.  If we don't, then we are being
  351.         ** called for the first time.  When the main window is
  352.         ** initially opened, it has the lineEdit controls from
  353.         ** the tabs window as well.  This is so that we can
  354.         ** initially get the data for the tabs window.  We need
  355.         ** to get the data at this point because the user may
  356.         ** not ever choose to open the tabs window.  Once the
  357.         ** main window is opened and the data is extracted, the
  358.         ** tabs window controls will be disposed.
  359.         */
  360.  
  361.     fmdLEGetText(wptr, TabChr, print.tabsData);
  362.         /* Use print.tabsData as a workspace. */
  363.  
  364.     if (!fmdGetError()) {
  365.         i = atoi(print.tabsData + 1) & 0xFF;
  366.         if (!i) i = 9;
  367.         if (i > 255) i = 9;
  368.         print.tabChr = i;
  369.     }
  370.  
  371.     fmdLEGetText(wptr, TabsData, print.tabsData);
  372.         /* Now use print.tabsData for real. */
  373. }
  374.  
  375. /**********************************************************************/
  376.  
  377. void    mainWindowDraw()
  378. {
  379.     fmdStdDrawProc();
  380.  
  381.     /* This routine is here as an example, even though we don't need it.
  382.     ** If you pass a NULL to fakeModalDialog as the updateProc, then
  383.     ** fakeModalDialog uses fmdStdDrawProc.  You can override this by
  384.     ** supplying your own.  If you supply your own, you can still have
  385.     ** fakeModalDialog do the standard stuff, simply by calling
  386.     ** fmdStdDrawProc yourself.  If we then had any additional stuff to
  387.     ** do, we could then do it here as well.  In this example, since we
  388.     ** aren't doing anything beyond calling fmdStdDrawProc, we could
  389.     ** have simply passed fakeModalDialog a NULL.
  390.     */
  391. }
  392.